package com.checkbox;

import com.checkbox.widgetset.SelectableTree;
import com.checkbox.widgetset.SelectableTreeNode;
import com.vaadin.annotations.Theme;
import com.vaadin.annotations.VaadinServletConfiguration;
import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.server.VaadinRequest;
import com.vaadin.server.VaadinServlet;
import com.vaadin.ui.Button;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Component;
import com.vaadin.ui.Label;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.annotation.WebServlet;

@Theme("checkboxtree")
@SuppressWarnings("serial")
public class CheckboxVaadinUI extends UI {
  @WebServlet(value = "/*", asyncSupported = true)
  @VaadinServletConfiguration(productionMode = false, ui = CheckboxVaadinUI.class, widgetset = "com.checkbox.AppWidgetSet")
  public static class Servlet extends VaadinServlet {
  }

  @Override
  protected void init(VaadinRequest request) {
    final VerticalLayout layout = new VerticalLayout();
    layout.setMargin(true);
    setContent(layout);
    Button button = new Button("Click Me");
    button.addClickListener(new Button.ClickListener() {
      public void buttonClick(ClickEvent event) {
        layout.addComponent(new Label("Thank you for clicking"));
      }
    });
    layout.addComponent(button);
    SelectableTree tableTree = new SelectableTree();
    tableTree.setWidth("100%");
    tableTree.setHeight("100%");
    layout.addComponent(tableTree);
    construct(tableTree);
    
    
//    layout.addComponent(new Label("demo!!!"));
  }

  private ArrayList<UiBeanItem<Integer>> getmockdata() {
    ArrayList<UiBeanItem<Integer>> beanList = new ArrayList<UiBeanItem<Integer>>();
    UiBeanItem<Integer> uibean = new UiBeanItem<Integer>();
    uibean.setId(1);
    uibean.setDisplayName("_" + 1);
    ArrayList<UiBeanItem<Integer>> ret = new ArrayList<UiBeanItem<Integer>>();
    for (int j = 11; j < 14; j++) {
      UiBeanItem<Integer> child = new UiBeanItem<Integer>();
      child.setId(j);
      child.setDisplayName("_" + j);
      ret.add(child);
    }
    
    uibean.setChildren(ret);
    beanList.add(uibean);
    return beanList;
  }

  protected void construct(SelectableTree tableTree) {
    for (UiBeanItem<Integer> item : getmockdata()) {
      SelectableTreeNode node = tableTree.addChild(item, item.getDisplayName(), item);
      node.setDescription(item.getDisplayName());
      node.setSelect(item.isSelected());
      addTreeNodeListener(node);
      if (item.getChildren().size() > 0) {
        construct(item.getChildren(), node);
      }
    }
  }

  protected void construct(List<UiBeanItem<Integer>> itemList, SelectableTreeNode parentNode) {
    for (UiBeanItem<Integer> item : itemList) {
      SelectableTreeNode node = parentNode.addChild(item, item.getDisplayName(), item);
      node.setDescription(item.getDisplayName());
      node.setSelect(item.isSelected());
      addTreeNodeListener(node);
      if (item.getChildren().size() > 0) {
        construct(item.getChildren(), node);
      }
    }
  }

  protected void addTreeNodeListener(final SelectableTreeNode node) {
    ValueChangeListener listener = new ValueChangeListener() {
      @Override
      public void valueChange(ValueChangeEvent event) {
        setTreeNodeSelect(node, (Boolean) event.getProperty().getValue());
        setParentTreeNodeSelect(node, (Boolean) event.getProperty().getValue());
      }
    };
    node.setImmediate(true);
    node.addValueChangeListener(listener);
  }

  private void setTreeNodeSelect(SelectableTreeNode node, Boolean select) {
    node.setImmediate(false);
    node.setSelect(select);
    UiBeanItem<Integer> item = (UiBeanItem<Integer>) node.getItemId();
    item.setSelected(select);
    setTreeNodeSelect(node.iterator(), select);
    node.setImmediate(true);
  }

  private void setTreeNodeSelect(Iterator<Component> treeComponents, Boolean select) {
    while (treeComponents.hasNext()) {
      Component comp = treeComponents.next();
      if (comp instanceof SelectableTreeNode) {
        SelectableTreeNode node = (SelectableTreeNode) comp;
        node.setSelect(select);
        setTreeNodeSelect(node, select);
      }
    }
  }

  private void setParentTreeNodeSelect(SelectableTreeNode node, Boolean select) {
    if (node.getParent().getClass() == SelectableTreeNode.class) {
      SelectableTreeNode parent = (SelectableTreeNode) node.getParent();
      if (parent.isSelect() != select) {
        Iterator<Component> treeComponents = parent.iterator();
        boolean matchParentNode = true;
        while (treeComponents.hasNext()) {
          Component comp = treeComponents.next();
          if (comp instanceof SelectableTreeNode) {
            SelectableTreeNode childNode = (SelectableTreeNode) comp;
            if (childNode.isSelect() != select) {
              matchParentNode = false;
            }
          }
        }
        if (matchParentNode) {
          parent.setImmediate(false);
          parent.setSelect(select);
          UiBeanItem<Integer> item = (UiBeanItem<Integer>) parent.getItemId();
          item.setSelected(select);
          parent.setImmediate(true);
          setParentTreeNodeSelect(parent, select);
        } else {// children nodes have different states.
          parent.setImmediate(false);
          parent.setSelect(false);
          UiBeanItem<Integer> item = (UiBeanItem<Integer>) parent.getItemId();
          item.setSelected(false);
          parent.setImmediate(true);
          setParentTreeNodeSelect(parent, false);
        }
      }
    }
  }
}
